package com.admin.application;

import com.admin.domain.model.SelectRole;
import com.admin.domain.model.User;
import com.admin.domain.repository.RoleRepository;
import com.admin.domain.repository.UserDao;
import com.admin.domain.repository.UserRepository;
import com.admin.domain.service.RoleSelectService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;


/**
 * @author Jonsy
 */
@Service
@CacheConfig( cacheNames = "user" )
public class UserService {
    @Autowired
    protected UserRepository userRepository;
    @Autowired
    protected Md5PasswordEncoder md5PasswordEncoder;
    @Autowired
    protected RoleSelectService roleSelectService;
    @Autowired
    protected RoleRepository roleRepository;
    @Autowired
    protected UserDao userDao;

    @Caching(
            put = @CachePut( key = "#user.id" ),
            evict = @CacheEvict( value = "user-list", key = "'list'" )
    )
    public User create(User user){
        validate(user);
        Assert.hasText(user.getPassword());
        //user和密码的非空非root判断。
        user.setDisabled(false);
        user.setCreateTime(new Date());
        user.setSalt(RandomStringUtils.randomAscii(10));
        user.setPassword(md5PasswordEncoder.encodePassword(user.getPassword(), user.getSalt()));
        //这是jdbc的方法；service层调dao层。
        // userRepository.add(user);
        //这是jpa的方法；调dao层。
        userDao.save(user);
        return user;
    }


    @Caching(
            put = @CachePut( key = "#user.id" ),
            evict = @CacheEvict( value = "user-list", key = "'list'" )
    )
    public User modify(User user){
        Assert.hasText(user.getId());
        User old = get(user.getId());
        if(StringUtils.isNotBlank(user.getUsername())){
            old.setUsername(user.getUsername());
        }
        if(StringUtils.isNotBlank(user.getPassword())){
            old.setPassword(md5PasswordEncoder.encodePassword(user.getPassword(), old.getSalt()));
        }
        if(StringUtils.isNotBlank(user.getEmail())){
            old.setEmail(user.getEmail());
        }
        userRepository.update(old);
        return user;
    }

    @Caching(
            evict = {@CacheEvict( value = "user-list", key = "'list'" ), @CacheEvict( key = "#id" )}
    )
    public void delete(String id){
        userRepository.remove(id);
    }

    @Cacheable
    public User get(String id){
        return userRepository.get(id);
    }

    @Cacheable( value = "user-list", key = "'list'" )
    public List<User> list(){
        return userRepository.list();
    }

    @Caching(
            evict = {@CacheEvict( value = "user-list", key = "'list'" ), @CacheEvict( key = "#id" )}
    )
    public void switchStatus(String id, boolean disable){
        userRepository.switchStatus(id, disable);
    }

    @Caching(
            evict = {@CacheEvict( value = "user-nav-menu", key = "#uid" )}
    )
    public void grantRole(String uid, List<String> roleIds){
        userRepository.updateRoles(uid, roleIds);
    }

    //非空和非root判断！！~~~
    private void validate(User user){
        Assert.hasText(user.getUsername());
        /**
         * assert是断言，一个正确的程序必须保证是true；一般来说，assertion用于保证程序最基本、关键的正确性。
         assertion检查通常在开发和测试时开启。为了提高性能，在软件发布后，assertion检查通常是关闭的。
         也可说是指针非空。
         */
        if(user.isRoot()){
            throw new IllegalArgumentException("user loginName cannot is root");
        }
    }

    public List<SelectRole> selectRoles(String uid){
        return roleSelectService.mergeRole(roleRepository.list(), roleRepository.getRoles(uid));
    }

    public List<User> getUserByUname(String username){
        return userRepository.getUserByUname(username);
    }

    public List<User> getUserByEmail(String email){
        return userRepository.getUserByEmail(email);
    }

}
